home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / admin / xinetd.2 / xinetd / xinetd.2.1.7-linux.4 / libs / src / timer / sysdep.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-07-25  |  7.3 KB  |  329 lines

  1. /*
  2.  * (c) Copyright 1993 by Panagiotis Tsirigotis
  3.  * All rights reserved.  The file named COPYRIGHT specifies the terms 
  4.  * and conditions for redistribution.
  5.  */
  6.  
  7. #include <signal.h>
  8. #include <sys/time.h>
  9. #include <sys/resource.h>
  10.  
  11. #include "defs.h"
  12. #include "impl.h"
  13. #include "ostimer.h"
  14. #include "timemacros.h"
  15.  
  16.  
  17. PRIVATE void sigalrm_handler() ;
  18. PRIVATE void sigvtalrm_handler() ;
  19. PRIVATE void sigprof_handler() ;
  20.  
  21. PRIVATE void get_real_time() ;
  22. PRIVATE void get_virtual_time() ;
  23. PRIVATE void get_prof_time() ;
  24.  
  25. #define SIGNOSIG                            0
  26.  
  27. static struct os_timer os_timers[] =
  28.    {
  29. #ifdef ITIMER_REAL
  30.         { AVAILABLE,     ITIMER_REAL,
  31. #else
  32.         { UNAVAILABLE,    0,
  33. #endif
  34.             TIMER_REAL,            SIGALRM,    sigalrm_handler,     get_real_time     },
  35.  
  36. #ifdef ITIMER_VIRTUAL
  37.         { AVAILABLE,    ITIMER_VIRTUAL,
  38. #else
  39.         { UNAVAILABLE,    0,
  40. #endif
  41.         TIMER_VIRTUAL,        SIGVTALRM,  sigvtalrm_handler,   get_virtual_time  },
  42.  
  43. #ifdef ITIMER_PROF
  44.         { AVAILABLE,    ITIMER_PROF,
  45. #else
  46.         { UNAVAILABLE,    0,
  47. #endif
  48.         TIMER_PROF,         SIGPROF,    sigprof_handler,     get_prof_time     },
  49.  
  50.         { UNAVAILABLE,    0,
  51.         TIMER_REAL,            SIGNOSIG,    NULL,                NULL,             }
  52.    } ;
  53.  
  54.  
  55. /*
  56.  * The timer_block_mask blocks all timer signals when a timer signal
  57.  * happens (using the sa_mask field of struct sigaction). This is necessary
  58.  * when the user function associated with the timer does not return.
  59.  * Consider the following scenario:
  60.  *    The user creates 2 timers, one TIMER_REAL (signal: SIGALRM), one
  61.  *    TIMER_VIRTUAL (signal: SIGVTALRM).
  62.  *    SIGALRM occurs first but before it is handled, SIGVTALRM happens.
  63.  *    At this point both SIGARLM and SIGVTALRM are blocked.
  64.  *    SIGVTALRM gets unblocked and the function for the TIMER_VIRTUAL is
  65.  *    invoked and never returns. The function for the TIMER_REAL is never
  66.  *    invoked (and any TIMER_REAL timers never expire).
  67.  */
  68. #ifndef NO_POSIX_SIGS
  69. static sigset_t timer_block_mask ;
  70. #else
  71. static int timer_block_mask ;
  72. #endif
  73.  
  74. static int timer_block_mask_set ;         /* flag */
  75.  
  76.  
  77. /*
  78.  * Initialize the timer_block_mask.
  79.  * As a side-effect it also initializes the block_mask of each ostimer.
  80.  */
  81. PRIVATE void set_timer_block_mask()
  82. {
  83.    ostimer_s *otp ;
  84.  
  85. #ifndef NO_POSIX_SIGS
  86.    (void) sigemptyset( &timer_block_mask ) ;
  87. #else
  88.     /* timer_block_mask is a global variable so it is initialized to 0 */
  89. #endif
  90.  
  91.    for ( otp = &os_timers[ 0 ] ; otp->ost_handler ; otp++ )
  92.    {
  93. #ifndef NO_POSIX_SIGS
  94.       (void) sigemptyset( &otp->ost_block_mask ) ;
  95.       (void) sigaddset( &otp->ost_block_mask, otp->ost_signal ) ;
  96.       (void) sigaddset( &timer_block_mask, otp->ost_signal ) ;
  97. #else
  98.       otp->ost_block_mask = sigmask( otp->ost_signal ) ;
  99.       timer_block_mask |= otp->ost_block_mask ;
  100. #endif
  101.    }
  102.  
  103.    timer_block_mask_set = TRUE ;
  104. }
  105.  
  106.  
  107. PRIVATE ostimer_s *ostimer_find( type )
  108.     enum timer_types    type ;
  109. {
  110.     register ostimer_s *otp ;
  111.  
  112.     for ( otp = os_timers ; otp->ost_handler ; otp++ )
  113.         if ( otp->ost_timertype == type )
  114.             return( otp->ost_availability == AVAILABLE ? otp : OSTIMER_NULL ) ;
  115.     return( OSTIMER_NULL ) ;
  116. }
  117.  
  118.  
  119. PRIVATE int time_compare( p1, p2 )
  120.    pq_obj p1, p2 ;
  121. {
  122.    return( TV_LT( TP( p1 )->t_expiration, TP( p2 )->t_expiration ) ) ;
  123. }
  124.  
  125.  
  126. /*
  127.  * Initialize an OS timer. The initialization steps are:
  128.  *
  129.  *    create priority queue
  130.  *    install signal handler
  131.  *
  132.  * We also initialize the timer_block_mask if it has not been initialized yet.
  133.  */
  134. ostimer_s *__ostimer_init( tp, type )
  135.     timer_s                *tp ;
  136.     enum timer_types    type ;
  137. {
  138. #ifndef NO_POSIX_SIGS
  139.    struct sigaction  sa ;
  140. #else
  141.    struct sigvec     sv ;
  142. #endif
  143.    ostimer_s           *otp ;
  144.    struct timer_q    *tqp ;
  145.  
  146.     /*
  147.      * Find the corresponding ostimer
  148.      */
  149.     if ( ( otp = ostimer_find( type ) ) == OSTIMER_NULL )
  150.         HANDLE_ERROR( tp->t_flags, OSTIMER_NULL,
  151.             tp->t_errnop, TIMER_ENOTAVAILABLE,
  152.                 "TIMER __ostimer_init: requested timer type not available\n" ) ;
  153.  
  154.     /*
  155.      * We use the value of ost_timerq to determine if the os_timer
  156.      * has been initialized.
  157.      */
  158.    tqp = &otp->ost_timerq ;
  159.     if ( tqp->tq_handle )
  160.         return( otp ) ;
  161.     
  162.    tqp->tq_handle = pq_create( time_compare,
  163.                 tp->t_flags & TIMER_RETURN_ERROR ? PQ_RETURN_ERROR : PQ_NOFLAGS,
  164.                                         &tqp->tq_errno ) ;
  165.    if ( tqp->tq_handle == NULL )
  166.    {
  167.       *tp->t_errnop = TIMER_ENOMEM ;
  168.       return( OSTIMER_NULL ) ;
  169.    }
  170.  
  171.    if ( ! timer_block_mask_set )
  172.       set_timer_block_mask() ;
  173.  
  174. #ifndef NO_POSIX_SIGS
  175.    sa.sa_handler = otp->ost_handler ;
  176.    sa.sa_mask = timer_block_mask ;
  177.    sa.sa_flags = 0 ;
  178.    if ( sigaction( otp->ost_signal, &sa, SIGACTION_NULL ) == -1 )
  179. #else
  180.    sv.sv_handler = otp->ost_handler ;
  181.    sv.sv_mask = timer_block_mask ;
  182.    sv.sv_flags = 0 ;
  183.    if ( sigvec( otp->ost_signal, &sv, SIGVEC_NULL ) == -1 )
  184. #endif
  185.       HANDLE_ERROR( tp->t_flags, OSTIMER_NULL, tp->t_errnop, TIMER_ESIGPROBLEM,
  186.          "TIMER __ostimer_init: signal handler installation failed\n" ) ;
  187.    return( otp ) ;
  188. }
  189.  
  190.  
  191. /*
  192.  * timer_* functions that need access to private data of ostimer
  193.  */
  194. void timer_block_type( type )
  195.    enum timer_types    type ;
  196. {
  197.    ostimer_s            *otp = ostimer_find( type ) ;
  198.  
  199.     if ( otp == OSTIMER_NULL )
  200.         return ;
  201.  
  202. #ifndef NO_POSIX_SIGS
  203.    (void) sigprocmask( SIG_BLOCK, &otp->ost_block_mask, SIGSET_NULL ) ;
  204. #else
  205.    (void) sigblock( otp->ost_block_mask ) ;
  206. #endif
  207. }
  208.  
  209.  
  210. void timer_unblock_type( type )
  211.    enum timer_types    type ;
  212. {
  213.    ostimer_s            *otp = ostimer_find( type ) ;
  214.  
  215.     if ( otp == OSTIMER_NULL )
  216.         return ;
  217.  
  218. #ifndef NO_POSIX_SIGS
  219.    (void) sigprocmask( SIG_UNBLOCK, &otp->ost_block_mask, SIGSET_NULL ) ;
  220. #else
  221.     {
  222.         int old_mask = sigblock( ~0 ) ;
  223.  
  224.         (void) sigsetmask( old_mask & ~otp->ost_block_mask ) ;
  225.     }
  226. #endif
  227. }
  228.  
  229.  
  230. void __ostimer_blockall()
  231. {
  232. #ifndef NO_POSIX_SIGS
  233.    (void) sigprocmask( SIG_BLOCK, &timer_block_mask, SIGSET_NULL ) ;
  234. #else
  235.    (void) sigblock( timer_block_mask ) ;
  236. #endif
  237. }
  238.  
  239.  
  240. void __ostimer_unblockall()
  241. {
  242. #ifndef NO_POSIX_SIGS
  243.    (void) sigprocmask( SIG_UNBLOCK, &timer_block_mask, SIGSET_NULL ) ;
  244. #else
  245.    int old_mask = sigblock( ~0 ) ;
  246.  
  247.    (void) sigsetmask( old_mask & ~timer_block_mask ) ;
  248. #endif
  249. }
  250.  
  251.  
  252. void __ostimer_unblockall_except( otp )
  253.    ostimer_s *otp ;
  254. {
  255. #ifndef NO_POSIX_SIGS
  256.    sigset_t new_mask = timer_block_mask ;
  257.  
  258.    (void) sigdelset( &new_mask, otp->ost_signal ) ;
  259.    (void) sigprocmask( SIG_UNBLOCK, &new_mask, SIGSET_NULL ) ;
  260. #else
  261.    int old_mask = sigblock( ~0 ) ;
  262.  
  263.    (void) sigsetmask( ( old_mask & ~timer_block_mask )
  264.                                           | otp->ost_block_mask ) ;
  265. #endif
  266. }
  267.  
  268.  
  269. PRIVATE void sigalrm_handler()
  270. {
  271. #ifdef DEBUG_MSGS
  272.    printf( "\tSIGALRM happened\n" ) ;
  273. #endif
  274.    __ostimer_interrupt( &os_timers[ (int)TIMER_REAL ] ) ;
  275. }
  276.  
  277.  
  278. PRIVATE void sigvtalrm_handler()
  279. {
  280. #ifdef DEBUG_MSGS
  281.    printf( "\tSIGVTALRM happened\n" ) ;
  282. #endif
  283.    __ostimer_interrupt( &os_timers[ (int)TIMER_VIRTUAL ] ) ;
  284. }
  285.  
  286.  
  287. PRIVATE void sigprof_handler()
  288. {
  289. #ifdef DEBUG_MSGS
  290.    printf( "\tSIGPROF happened\n" ) ;
  291. #endif
  292.    __ostimer_interrupt( &os_timers[ (int)TIMER_PROF ] ) ;
  293. }
  294.  
  295.  
  296. PRIVATE void get_real_time( tvp )
  297.    struct timeval *tvp ;
  298. {
  299. #ifdef ITIMER_REAL
  300.    (void) gettimeofday( tvp, TIMEZONE_NULL ) ;
  301. #endif
  302. }
  303.  
  304.  
  305. PRIVATE void get_virtual_time( tvp )
  306.    struct timeval *tvp ;
  307. {
  308. #ifdef ITIMER_VIRTUAL
  309.    struct rusage ru ;
  310.  
  311.    (void) getrusage( RUSAGE_SELF, &ru ) ;
  312.    *tvp = ru.ru_utime ;
  313. #endif
  314. }
  315.  
  316.  
  317. PRIVATE void get_prof_time( tvp )
  318.    struct timeval *tvp ;
  319. {
  320. #ifdef ITIMER_PROF
  321.    struct rusage ru ;
  322.  
  323.    (void) getrusage( RUSAGE_SELF, &ru ) ;
  324.    TV_ADD( *tvp, ru.ru_utime, ru.ru_stime ) ;
  325. #endif
  326. }
  327.  
  328.  
  329.